package com.cruel_wandering.wifi_geo_predictor.location;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;

public class MyLocationManager
{
	/**
	 * Name of the GPS location provider.
	 * Taken from {@link LocationManager.GPS_PROVIDER}
	 */
	static public String GPS_PROVIDER = LocationManager.GPS_PROVIDER;

	/**
	 * Key used for a Bundle extra holding a Location value when a location
	 * change is broadcast using a PendingIntent.
	 * Taken from {@link LocationManager.KEY_LOCATION_CHANGED}
	 */
	static public String KEY_LOCATION_CHANGED =
	  LocationManager.KEY_LOCATION_CHANGED;

	/**
	 * Key used for a Bundle extra holding an Boolean status value when a
	 * provider enabled/disabled event is broadcast using a PendingIntent.
	 * Taken from {@link LocationManager.KEY_PROVIDER_ENABLED}
	 */
	static public String KEY_PROVIDER_ENABLED =
	  LocationManager.KEY_PROVIDER_ENABLED;

	/**
	 * Key used for the Bundle extra holding a boolean indicating whether a
	 * proximity alert is entering (true) or exiting (false)..
	 * Taken from {@link LocationManager.KEY_PROXIMITY_ENTERING}
	 */
	static public String KEY_PROXIMITY_ENTERING =
	  LocationManager.KEY_PROXIMITY_ENTERING;

	/**
	 * Key used for a Bundle extra holding an Integer status value when a
	 * status change is broadcast using a PendingIntent.
	 * Taken from {@link LocationManager.KEY_STATUS_CHANGED}
	 */
	static public String KEY_STATUS_CHANGED =
	  LocationManager.KEY_STATUS_CHANGED;

	/**
	 * Name of the network location provider.
	 * Taken from {@link LocationManager.NETWORK_PROVIDER}
	 */
	static public String NETWORK_PROVIDER = LocationManager.NETWORK_PROVIDER;

	static MyLocationManager instance = null;

	/**
	 * Get instance of {@link MyLocationProvider}
	 * @param ctx current context
	 * @return
	 */
	static public MyLocationManager getInstance(Context ctx)
	{
		if (instance == null)
			instance = new MyLocationManager(ctx);
		return instance;
	}

/*	private LocationManager lm = null;*/
	private Map<String, MyLocationProvider> providers;

	private MyLocationManager(Context ctx)
  {
		providers = new HashMap<String, MyLocationProvider>();

		providers.put(GPS_PROVIDER, new MyGPSProvider(ctx));
		providers.put(NETWORK_PROVIDER, new MyCellIDProvider(ctx));
/*		lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);*/
  }

	/**
	 * Returns a list of the names of all known location providers.
	 * Taken from {@link LocationManager.<tring}
	 */
	public List<String> getAllProviders()
	{
		return new ArrayList<String>(providers.keySet());
	}

	/**
	 * Returns the name of the provider that best meets the given criteria.
	 * Taken from {@link LocationManager.getBestProvider}
	 */
	public String getBestProvider(Criteria criteria, boolean enabledOnly)
	{
		List<String> list = getProviders(criteria, enabledOnly);

		/* XXX: Currently, there are only 2 providers, and we prefer GPS over
		 * CellID, when both are available. */
		return (list.contains(GPS_PROVIDER)) ? GPS_PROVIDER : NETWORK_PROVIDER;
	}

	/**
	 * Returns a Location indicating the data from the last known location
	 * fix obtained from the given provider.
	 * Taken from {@link Location.getLastKnownLocation}
	 */
	public Location getLastKnownLocation(String provider)
	{
		MyLocationProvider p = providers.get(provider);

		if (p == null)
			return null;

		return p.getLastKnownLocation();
	}

	/**
	 * Returns the information associated with the location provider of the
	 * given name, or null if no provider exists by that name.
	 * Taken from {@link Location.getProvider}
	 */
	public MyLocationProvider getProvider(String name)
	{
		return providers.get(name);
	}

	/**
	 * Returns a list of the names of LocationProviders that satisfy the
	 * given criteria, or null if none do.
	 * Taken from {@link LocationProviders.<tring}
	 */
	public List<String> getProviders(Criteria criteria,
	  boolean enabledOnly)
	{
		List<String> list = new ArrayList<String>();

		for (String key : providers.keySet())
		{
			MyLocationProvider p = providers.get(key);

			if (enabledOnly && !p.isEnabled())
				continue;

			if (p.meetsCriteria(criteria))
				list.add(key);
		}
		return list;
	}

	/**
	 * Returns a list of the names of location providers.
	 * Taken from {@link LocationProviders.<tring}
	 */
	public List<String> getProviders(boolean enabledOnly)
	{
		if (!enabledOnly)
			return new ArrayList<String>(providers.keySet());

		List<String> list = new ArrayList<String>();

		for (String key : providers.keySet())
		{
			if (providers.get(key).isEnabled())
				list.add(key);
		}
		return list;
	}

	/**
	 * Returns the current enabled/disabled status of the given provider.
	 * Taken from {@link LocationProviders.isProviderEnabled}
	 */
	public boolean isProviderEnabled(String provider)
	{
		MyLocationProvider p = providers.get(provider);

		if (p == null)
			return false;

		return p.isEnabled();
	}

	/**
	 * Registers the current activity to be notified periodically by the
	 * named provider.
	 * Taken from {@link LocationListener.requestLocationUpdates}
	 */
	public void requestLocationUpdates(String provider, long minTime,
	  float minDistance, LocationListener listener)
	{
		MyLocationProvider p = providers.get(provider);

		if (p == null)
			return;

		p.requestLocationUpdates(minTime, minDistance, listener);
	}

	/**
	 * Removes any current registration for location updates of the current
	 * activity with the given LocationListener.
	 * Taken from {@link LocationListener.removeUpdates}
	 */
	public void removeUpdates(LocationListener listener)
	{
		for (String key : providers.keySet())
		{
			providers.get(key).removeUpdates(listener);
		}
	}

	/*
		|**
		 * A special location provider for receiving locations without actually
		 * initiating a location fix.
		 * Taken from {@link LocationManager.PASSIVE_PROVIDER}
		 *|
		public String PASSIVE_PROVIDER = LocationManager.PASSIVE_PROVIDER;

		|**
		 * Adds a GPS status listener.
		 * Taken from {@link LocationManager.addGpsStatusListener}
		 *|
		public boolean addGpsStatusListener(GpsStatus.Listener listener);

		|**
		 * Adds an NMEA listener.
		 * Taken from {@link LocationManager.addNmeaListener}
		 *|
		public boolean addNmeaListener(GpsStatus.NmeaListener listener);

		|**
		 * Sets a proximity alert for the location given by the position
		 * (latitude, longitude) and the given radius.
		 * Taken from {@link LocationManager.addProximityAlert}
		 *|
		void addProximityAlert(double latitude, double longitude, float radius,
		  public long expiration, PendingIntent intent);

		|**
		 * Creates a mock location provider and adds it to the set of active
		 * providers.
		 * Taken from {@link LocationManager.addTestProvider}
		 *|
		void addTestProvider(String name, boolean requiresNetwork,
		  boolean requiresSatellite, boolean requiresCell,
		  boolean hasMonetaryCost, boolean supportsAltitude,
		  boolean supportsSpeed, boolean supportsBearing, int powerRequirement,
		  public int accuracy);

		|**
		 * Removes any mock enabled value associated with the given provider.
		 * Taken from {@link LocationManager.clearTestProviderEnabled}
		 *|
		public void clearTestProviderEnabled(String provider);

		|**
		 * Removes any mock location associated with the given provider.
		 * Taken from {@link LocationManager.clearTestProviderLocation}
		 *|
		public void clearTestProviderLocation(String provider);

		|**
		 * Removes any mock status values associated with the given provider.
		 * Taken from {@link LocationManager.clearTestProviderStatus}
		 *|
		public void clearTestProviderStatus(String provider);

	|**
	 * Retrieves information about the current status of the GPS engine.
	 * Taken from {@link LocationManager.getGpsStatus}
	 *|
	public GpsStatus getGpsStatus(GpsStatus status);

	|**
	 * Removes a GPS status listener.
	 * Taken from {@link LocationProviders.removeGpsStatusListener}
	 *|
	public void removeGpsStatusListener(GpsStatus.Listener listener);

	|**
	 * Removes an NMEA listener.
	 * Taken from {@link LocationProviders.removeNmeaListener}
	 *|
	public void removeNmeaListener(GpsStatus.NmeaListener listener);

	|**
	 * Removes the proximity alert with the given PendingIntent.
	 * Taken from {@link LocationProviders.removeProximityAlert}
	 *|
	public void removeProximityAlert(PendingIntent intent)
	{
		lm.removeProximityAlert(intent);
	}

	|**
	 * Removes the mock location provider with the given name.
	 * Taken from {@link LocationProviders.removeTestProvider}
	 *|
	public void removeTestProvider(String provider)
	{
		lm.removeTestProvider(provider);
	}

	|**
	 * Removes any current registration for location updates of the current
	 * activity with the given PendingIntent.
	 * Taken from {@link LocationListener.removeUpdates}
	 *|
	public void removeUpdates(PendingIntent intent);

	|**
	 * Registers the current activity to be notified periodically by the
	 * named provider.
	 * Taken from {@link LocationListener.requestLocationUpdates}
	 *|
	public void requestLocationUpdates(String provider, long minTime,
	  float minDistance, PendingIntent intent)
	{
		MyLocationProvider p = providers.get(provider);

		if (p == null)
			return;

		p.requestLocationUpdates(minTime, minDistance, intent);
	}

	|**
	 * Registers the current activity to be notified periodically by the
	 * named provider.
	 * Taken from {@link LocationListener.requestLocationUpdates}
	 *|
	public void requestLocationUpdates(String provider, long minTime,
	  float minDistance, LocationListener listener, Looper looper)
	{
		MyLocationProvider p = providers.get(provider);

		if (p == null)
			return;

		p.requestLocationUpdates(minTime, minDistance, listener, looper);
	}

	|**
	 * Sends additional commands to a location provider.
	 * Taken from {@link LocationListener.sendExtraCommand}
	 *|
	public boolean sendExtraCommand(String provider, String command,
	  Bundle extras)
	{
		return lm.sendExtraCommand(provider, command, extras);
	}

	|**
	 * Sets a mock enabled value for the given provider.
	 * Taken from {@link LocationListener.setTestProviderEnabled}
	 *|
	public void setTestProviderEnabled(String provider, boolean enabled)
	{
		lm.setTestProviderEnabled(provider, enabled);
	}

	|**
	 * Sets a mock location for the given provider.
	 * Taken from {@link LocationListener.setTestProviderLocation}
	 *|
	public void setTestProviderLocation(String provider, Location loc)
	{
		lm.setTestProviderLocation(provider, loc);
	}

	|**
	 * Sets mock status values for the given provider.
	 * Taken from {@link Location.setTestProviderStatus}
	 *|
	public void setTestProviderStatus(String provider, int status,
	  Bundle extras, long updateTime)
	{
		lm.setTestProviderStatus(provider, status, extras, updateTime);
	}
*/
}
